﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace CameraWrapper
{
    public partial class SDK10000
    {
        static readonly MEDIA_CONNECTION_CONFIG2 DEFAULT = new MEDIA_CONNECTION_CONFIG2
        {
            ContactType = (int)CONTACT_TYPE.CONTACT_TYPE_UNICAST_PREVIEW,

            UniCastIP = "194.36.79.201",
            MultiCastIP = "172.16.1.82",

            UserID = "Admin",
            Password = "123456",

            ControlPort = 6001,
            HTTPPort = 80,
            MultiCastPort = 5000,
            RegisterPort = 6000,
            StreamingPort = 6002,

            ChannelNumber = 0,
            PlayFileName = "",
            ConnectTimeOut = 3,
        };

        #region INSTANCE
        #region CLASS
        /// <summary>
        /// Private CameraInfo Struct for Internal Instance use only
        /// </summary>
        public class CameraInfo
        {
            public string Name;
            public PictureBox PictureBox;
            public string UniCastIP;
            public string UserName;
            public string Password;
            public IntPtr Handle;
            public bool IsRecording;
            public bool IsPlaying;
            public string SavePath;

            CameraInfo(string name, PictureBox pictureBox, string uniCastIP, string userName, string password, IntPtr handle, bool isRecording, bool isPlaying, string savePath)
            {
                this.Name = name;
                this.PictureBox = pictureBox;
                this.UniCastIP = uniCastIP;
                this.UserName = userName;
                this.Password = password;
                this.Handle = handle;
                this.IsRecording = isRecording;
                this.IsPlaying = isPlaying;
                this.SavePath = savePath;
            }

            public CameraInfo(PictureBox pictureBox)
                : this(pictureBox, DEFAULT.MultiCastIP)
            { }

            public CameraInfo(PictureBox pictureBox, string IP)
                : this(pictureBox, IP, DEFAULT.UserID, DEFAULT.Password)
            { }

            public CameraInfo(PictureBox pictureBox, string IP, string saveFile)
                : this(pictureBox, IP, DEFAULT.UserID, DEFAULT.Password, saveFile)
            { }

            public CameraInfo(PictureBox pictureBox, string IP, string userName, string passWord, string saveFile = null, string cameraName = null)
                : this(cameraName, pictureBox, IP == null ? DEFAULT.UniCastIP : IP, userName == null ? DEFAULT.UserID : userName, passWord == null ? DEFAULT.Password : passWord, IntPtr.Zero, false, false, saveFile)
            { }

            
            internal MEDIA_CONNECTION_CONFIG2 MCC2
            {
                get
                {
                    MEDIA_CONNECTION_CONFIG2 medcon = DEFAULT;
                    medcon.UniCastIP = this.UniCastIP;
                    medcon.UserID = this.UserName;
                    medcon.Password = this.Password;
                    return medcon;
                }
            }

            internal MEDIA_RENDER_INFO MRI
            {
                get
                {
                    MEDIA_RENDER_INFO medren = new MEDIA_RENDER_INFO();
                    medren.rect.top = 0;
                    medren.rect.left = 0;
                    medren.rect.right = this.PictureBox.Width;//DisplayRectangle.Right - this.PictureBox.DisplayRectangle.Left;
                    medren.rect.bottom = this.PictureBox.Height;//DisplayRectangle.Bottom - this.PictureBox.DisplayRectangle.Top;
                    medren.hWnd = this.PictureBox.Handle;
                    return medren;
                }
            }
        }
        #endregion
        #region ENUM

        #endregion
        #region STRUCT
#if false
        /// <summary>
        /// When you create new Instance of class SDK10000, if you want to specify camera IP, username and password, you have to create a new instance of this struct and pass as Parameter.
        /// </summary>
        struct CameraConfig
        {
            /// <summary>
            /// The UniCast IP Address of the CameraServer
            /// </summary>
            public string UniCastIP;
            /// <summary>
            /// The UserName to login CameraServer
            /// </summary>
            public string UserName;
            /// <summary>
            /// A Password needed
            /// </summary>
            public string Password;

            /// <summary>
            /// Create new CameraConfig with FULL Parameter provided !
            /// </summary>
            /// <param name="UniCastIP"></param>
            /// <param name="UserName"></param>
            /// <param name="Password"></param>
            public CameraConfig(string UniCastIP, string UserName, string Password)
                : this()
            {
                this.UniCastIP = UniCastIP;
                this.UserName = UserName;
                this.Password = Password;
            }

            /// <summary>
            /// Create new CameraConfig with UniCastIP provided only. Default Username "Admin" and Password "123456" will be used !
            /// </summary>
            /// <param name="UniCastIP"></param>
            public CameraConfig(string UniCastIP)
                : this(UniCastIP, DEFAULT.UserID, DEFAULT.Password) { }

            // public const CameraConfig Defaults = new CameraConfig("194.36.79.201", "Admin", "123456");
            /// <summary>
            /// Defaults CameraConfig UniCastIP "194.36.79.201", Username "Admin" and Password "123456" will be used !
            /// </summary>
            public static CameraConfig Defaults
            {
                get { return new CameraConfig(DEFAULT.UniCastIP, DEFAULT.UserID, DEFAULT.Password); } // CHANGE HERE FOR DEFAULT VALUE
            }
        }
#endif
        #endregion
        #endregion

        #region SDK10000
        #region ENUM
        enum FILE_WRITER_TYPES		/** File writer types */
        {
            FRAW,					///< #0# - Record by *.Raw File - using FRAW
            FAVI,					///< #1# - Record by *.Avi File - using FAVI
            FRAW2					///< #1# - Record by *.Raw File with *.idx file - using FRAW2
        }

        enum CONTACT_TYPE
        {
            CONTACT_TYPE_UNUSE = 0,
            CONTACT_TYPE_UNICAST_WOC_PREVIEW = 1,
            CONTACT_TYPE_MULTICAST_WOC_PREVIEW,
            CONTACT_TYPE_RTSP_PREVIEW,
            CONTACT_TYPE_CONTROL_ONLY,
            CONTACT_TYPE_UNICAST_PREVIEW,
            CONTACT_TYPE_MULTICAST_PREVIEW,
            CONTACT_TYPE_PLAYBACK,
            CONTACT_TYPE_CARD_PREVIEW,

            CONTACT_TYPE_MULTIPLE_PLAYBACK,
            CONTACT_TYPE_HTTP_RTSP_WOC_PREVIEW,
            CONTACT_TYPE_HTTP_RTSP_PREVIEW,

            CONTACT_TYPE_HTTP,

            CONTACT_TYPE_RTSP_RTPUDP_PREVIEW,
            CONTACT_TYPE_RTSP_RTPUDP_WOC_PREVIEW,

            CONTACT_TYPE_HTTP_WOC_PREVIEW,
            CONTACT_TYPE_HTTP_PREVIEW,
            CONTACT_TYPE_HTTP_CONTROL_ONLY,
            CONTACT_TYPE_HTTP_MESSAGE, // dual session ; listen and POST Message
            CONTACT_TYPE_HTTP_REMOTE_PLAYBACK,         // Remote Playback (search/play)
            CONTACT_TYPE_HTTP_AUDIO_TRANSFER,          // Send Audio to Device

            CONTACT_TYPE_PLAYBACK_AVI = 60,

            CONTACT_TYPE_MAX,
        }
        #endregion
        #region STRUCT

        [StructLayout(LayoutKind.Sequential)]
        internal struct MEDIA_CONNECTION_CONFIG2
        {
            public int ContactType;

            public byte ChannelNumber;	// For URL Command CHANNEL tag, when set it to 0, URL command won't bring CHANNEL tag, or the URL command will bring CHANNEL=ChannelNumber tag  )
            public byte TCPVideoStreamID;	// 0 based to specify video track, value 0 to 255 for 1 to 256 video track
            public byte RTPVideoTrackNumber;	// set it to 0, ARTP will use 1st video track,  1 to 255 is for specify video track
            public byte RTPAudioTrackNumber;	// set it to 0, ARTP will use 1st audio track,  1 to 255 is for specify audio track

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string UniCastIP;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
            public string MultiCastIP;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string PlayFileName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string UserID;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string Password;
            /*[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public byte[] UniCastIP;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] MultiCastIP;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public byte[] PlayFileName;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] UserID;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] Password;*/

            public uint RegisterPort;
            public uint StreamingPort;
            public uint ControlPort;
            public uint MultiCastPort;
            public uint SearchPortC2S;
            public uint SearchPortS2C;
            public uint HTTPPort;
            public uint RTSPPort;
            public uint Reserved1;
            public uint Reserved2;

            public ushort ConnectTimeOut;
            public ushort EncryptionType;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct MEDIA_RENDER_INFO
        {
            public int DrawerInterface;
            public IntPtr hWnd;
            internal RECT rect;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct MP4FILE_RECORD_INFO
        {
            public uint tBeginTime;
            public uint tEndTime;
            public byte btTimeZone;
            public uint dwGOP;
            public uint dwFrameCount;
            public ulong FileSize;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RECT
        {
            public int left, top, right, bottom;
        }

        [StructLayout(LayoutKind.Explicit)]
        struct RECT2
        {
            [FieldOffset(0)]
            public int left;
            [FieldOffset(4)]
            public int top;
            [FieldOffset(8)]
            public int right;
            [FieldOffset(12)]
            public int bottom;
        }
        #endregion
        #endregion

        #region PInvoke SDK10000
        //http://msdn.microsoft.com/en-us/library/ac7ay120.aspx
        //http://msdn.microsoft.com/en-us/library/ms235282.aspx Convert Type in PInvoke


        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr KOpenInterface();

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KCloseInterface(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern bool KSetMediaConfig2(IntPtr h, ref MEDIA_CONNECTION_CONFIG2 MediaConfig);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern bool KConnect(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KDisconnect(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern bool KStartStreaming(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KStopStreaming(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KSetRenderInfo(IntPtr h, ref MEDIA_RENDER_INFO RenderInfo);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KPlay(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KPause(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KStop(IntPtr h);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KSetMute(IntPtr h, bool bMute);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KSetVolume(IntPtr h, int nLeftVolume, int nRightVolume);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KSetFileWriterType(IntPtr h, int nType);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern bool KStartRecord(IntPtr h, string FileName);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KSetPrerecordTime(IntPtr h, int nInSecond);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KStopRecord(IntPtr h, ref MP4FILE_RECORD_INFO mrec);

        [DllImport("KMpeg4.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern void KSetDecodeIFrameOnly(IntPtr h, bool decodeIonly);
        #endregion
    }
}



// BACKUP CODE
#if false
        static byte[] ToByteArray(string s, int size)
        {
            byte[] barr = new byte[size];
            char[] temp = s.ToCharArray();
            for (int i = 0; i < size; i++)
            {
                if (i < temp.Length) barr[i] = Convert.ToByte(temp[i]);
                else barr[i] = 0;
            }
            return barr;
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct MEDIA_CONNECTION_CONFIG
        {
            public int ContactType;

            public byte ChannelNumber;	// For URL Command CHANNEL tag, when set it to 0, URL command won't bring CHANNEL tag, or the URL command will bring CHANNEL=ChannelNumber tag  )
            public byte TCPVideoStreamID;	// 0 based to specify video track, value 0 to 255 for 1 to 256 video track
            public byte RTPVideoTrackNumber;	// set it to 0, ARTP will use 1st video track,  1 to 255 is for specify video track
            public byte RTPAudioTrackNumber;	// set it to 0, ARTP will use 1st audio track,  1 to 255 is for specify audio track

            /*[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string UniCastIP;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
            public string MultiCastIP;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string PlayFileName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string UserID;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
            public string Password;*/
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public byte[] UniCastIP;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
            public byte[] MultiCastIP;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
            public byte[] PlayFileName;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] UserID;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
            public byte[] Password;

            public uint RegisterPort;
            public uint StreamingPort;
            public uint ControlPort;
            public uint MultiCastPort;
            public uint SearchPortC2S;
            public uint SearchPortS2C;
            public uint HTTPPort;
            public uint RTSPPort;
            public uint Reserved1;
            public uint Reserved2;

            public ushort ConnectTimeOut;
            public ushort EncryptionType;
        }
#endif